package com.sunday.common.mq.rabbit.study.base.e5_Topics;

import com.rabbitmq.client.*;
import com.sunday.common.mq.rabbit.study.base.ConnectionUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.Scanner;

/**
 * 主题
 * <p>
 * 在前面的教程中，我们改进了我们的 日志记录系统。而不是使用只能 虚拟广播，我们使用了直接广播，并获得了可能性 有选择地接收日志。
 * 尽管使用直接交换改善了我们的系统，但它仍然具有 限制 - 它不能基于多个条件进行路由。
 * 在我们的日志系统中，我们可能不仅要订阅日志 基于严重性，但也基于发出日志的来源。 您可能从 syslog unix 工具中知道这个概念，该工具 根据严重性（信息/警告/暴击...）和设施路由日志 （auth/cron/kern...）。
 * 这将给我们很大的灵活性 - 我们可能想听 只有来自“cron”的严重错误，还有来自“kern”的所有日志。
 * 为了在我们的日志记录系统中实现这一点，我们需要了解更多 复杂的话题交流。
 * <p>
 * 话题交流
 * 发送到主题交换的消息不能有任意routing_key - 它必须是单词列表，由点分隔。这 单词可以是任何东西，但通常它们指定了一些特征 已连接到消息。
 * 一些有效的路由密钥示例： “stock.usd.nyse”， “nyse.vmw”， “quick.orange.rabbit”。可以有 路由密钥中随心所欲地包含多个单词，最多可达 255 个 字节。
 * 绑定密钥也必须采用相同的形式。主题交换背后的逻辑类似于直接交换 - 发送的消息带有 特定的路由密钥将被传递到所有队列 绑定匹配的绑定键。但是有两个重要的 绑定键的特殊情况：
 * <p>
 * *（星号）可以代替一个词。
 * #（哈希）可以替换零个或多个单词。
 * <p>
 * TOPIC("topic"),		主题模式
 * <p>
 * 将路由键和某模式进行匹配。此时队列需要绑定要一个模式上。
 * 符号“#”匹配一个或多个词，符号“*”匹配不多不少一个词。
 * 因此“audit.#”能够匹配到“audit.irs.corporate”，但是“audit.*” 只会匹配到“audit.irs”。
 * <p>
 * input -> *.orange.* *.*.rabbit lazy.#
 */
@Slf4j
public class ReceiveLogsTopic {

    private static final String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] argv) throws Exception {

        ConnectionFactory factory = ConnectionUtil.factory();

        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
        String queueName = channel.queueDeclare().getQueue();

        Scanner scan = new Scanner(System.in);//实例化Scanner对象
        log.info("请输入文本:");
        String input = scan.nextLine();//接受用户输入的字符串

        argv = input.split(" ");

        if (argv.length < 1) {
            System.err.println("Usage: ReceiveLogsTopic [binding_key]...");
            System.exit(1);
        }

        for (String bindingKey : argv) {
            channel.queueBind(queueName, EXCHANGE_NAME, bindingKey);
        }

        log.info(" [*] Waiting for messages. To exit press CTRL+C");

        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" + delivery.getEnvelope().getRoutingKey() + "':'" + message + "'");
        };
        channel.basicConsume(queueName, true, deliverCallback, consumerTag -> {
        });
    }
}

